/* 
 * File:   Game.cpp
 * Author: mvdr
 * 
 * Created on March 19, 2013, 3:01 PM
 */

#include "Game.h"
#include <algorithm>
#include <iostream>
#include <utility>
#include <queue>

using namespace std;

Game::Game(bool magic):
d_questionStack(0),
d_currState(0),
d_currPlayer(0),
d_magic(magic)
{    
    for (char i = 1; i != d_questions.size(); ++i)
        d_questionStack.push_back(i);    
}

void Game::run() {
    shuffleQuestions();
    d_model.initRelations();
    d_currState = rand() % d_model.numberOfStates();      
    startPlaying();    
}

void Game::shuffleQuestions() {
    random_shuffle(d_questionStack.begin(), d_questionStack.end());
}

void Game::startPlaying() {
    for (size_t turn = 0; turn != d_questionStack.size(); ++turn)    
    {   
        d_currPlayer = turn % 3;
        int currQuestion = d_questionStack[turn];
        
        State trueState = d_model.stateAt(d_currState);
        bool answer = d_questions.answer(d_currPlayer, currQuestion, trueState);        
        updateModel(answer, currQuestion);
        
        if(anybodyKnows())
        {
            cout << numberOfWinners() << " winner(s) after " << turn + 1 << " turns!!!\n";
            break;
        }
        else if (turn < d_questionStack.size() - 1 && d_magic)
            epistemagic();
        else if (turn == 3 * d_questionStack.size() - 1)
            cout << "No winners :-(\n";
            d_model.printRemainingStates(d_currState);
        }
        
        //printInfo();
        
        bool considerTrueStatePossible = 
        d_model.playerConsidersStatePossible(0, d_currState, d_currState) &
        d_model.playerConsidersStatePossible(1, d_currState, d_currState) &
        d_model.playerConsidersStatePossible(2, d_currState, d_currState);
        
        if (!considerTrueStatePossible)
            cout << "\nERROR!!! True state not considered possible by at " <<
                    "least one player!\n";
        
        if (d_verbose)
        {
            cout << "\r(continue)  \b\b";
            pauseTilEnter();         
        }
    }
    
}

void Game::updateModel(bool answer, int currQuestion) {
    for (size_t idx = 0; idx != d_model.numberOfStates(); ++idx) {
        State tempState = d_model.stateAt(idx);
        bool tempAnswer = d_questions.answer(d_currPlayer, currQuestion, tempState);
        if (tempAnswer != answer)
            for (size_t p = 0; p != 3; ++p)
                if (p != d_currPlayer)
                    d_model.cutOff(idx, p);
          
    }           
}

bool Game::anybodyKnows() const {    
    for (size_t p = 0; p != 3; ++p)
    {
        if (d_model.playerKnowsState(p, d_currState))
            return true;
    }
    return false;
}

size_t Game::numberOfWinners() const {
    size_t winners = 0;
    for (size_t p = 0; p != 3; ++p)
    {
        if (d_model.playerKnowsState(p, d_currState))
            ++winners;
    }
    
    return winners;
}

void Game::epistemagic() {
    vector<int> removeCandidates(0);
    
    for (int p = 0; p != 3; ++p)
        for (int s = 0; s != d_model.numberOfStates(); ++s)        
            if (d_model.playerKnowsState(p, s))                         
                removeCandidates.push_back(s);
     
    for (int i = 0; i != removeCandidates.size(); ++i)
        for (int p = 0; p != 3; ++p)
            d_model.cutOff(removeCandidates[i], p);
    
}

void Game::printInfo() const {
    for (int p = 0; p != 3; ++p) {
        cout << "Player " << (p + 1) << " could know " << d_model.knownStates(p) <<
                " states.\n";
    }
    
    for (int p = 0; p != 3; ++p) {
        cout << "Player " << p + 1 << " considers " << d_model.playerConsidersPossible(p, d_currState)
                << " states possible in the actual world.\n";
    }
}
